#NoTrayIcon

#Include <Array.au3>
#Include <Constants.au3>
#Include <File.au3>
#Include <Process.au3>
#Include <String.au3>

#Include <ButtonConstants.au3>
#Include <ComboConstants.au3>
#Include <EditConstants.au3>
#Include <GUIConstantsEx.au3>
#Include <GuiStatusBar.au3>
#Include <ProgressConstants.au3>
#Include <StaticConstants.au3>
#Include <WindowsConstants.au3>

; Special Settings
Opt( 'TrayMenuMode'    , 3 )
Opt( 'TrayOnEventMode' , 1 )

; Set HotKeys - CTRL+ALT+ESC
HotKeySet( '^!{ESC}' , '_Exit' )

; Create Tray Menu Items And Set The Events
$Show = TrayCreateItem( 'Show' )
TrayItemSetOnEvent( $Show , '_Show' )
TrayCreateItem('') ; Create a separator line.
$Exit = TrayCreateItem( 'Exit' )
TrayItemSetOnEvent( $Exit , '_Exit' )
; Set the action if you left click on the tray icon
TraySetOnEvent( $TRAY_EVENT_PRIMARYUP , '_Show' )
; Show the menu if the icon is right clicked
TraySetClick( 8 )

Global $AppVersion = '1.40'

Global $Complete , $FileDir , $FileExt , $FileName , $FinalExt , $Parent , $ShortName
Global $String_AVI_File , $String_MKV_File , $String_MP4_File
Global $Precent_1  , $Precent_2  , $Precent_3
Global $Progress_1 , $Progress_2 , $Progress_3
Global $Count_Files , $Count_Errors , $ErrorLog , $File_Count , $TempFolder , $GUIFinalExt , $Quality
Global $Streams_All , $Stream_Count , $Streams_Count_All
Global $Initial_Time
Global $Size_Old = 0 , $Size_New = 0
Global $SavedSettings = @ScriptDir & '\Settings.ini'

Dim $Extensions= '*.3gp;*.avi;*.avs;*.divx;*.f4v;*.flv;*.m4v;*.mkv;*.mp4;*.mpg;*.ogm;*.vob'

Dim $Quality_V = '00|01|02|03|04|05|06|07|08|09|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31|32|33|34|35|36|37|38|39|40|41|42|43|44|45|46|47|48|49|50'
Dim $Preset    = 'UltraFast|SuperFast|VeryFast|Faster|Fast|Medium|Slow|Slower|VerySlow|Placebo'
Dim $Tuning    = 'Animation|FastDecode|Film|Grain|PSNR|SSIM|StillImage|ZeroLatency'
; FHGaacEnc
;Dim $Quality_A= '01|02|03|04|05|06'
; Qaac
;Dim $Quality_A = '06|12|18|24|30|36|42|48|54|60|66|72|78|84|90|96|102|108|114|120|126'
; LAME
Dim $Quality_A= '01|02|03|04|05|06|07|08|09'

; Create Basic Settings If Required
If NOT FileExists( $SavedSettings ) Then _BasicSettings()

; Create List of Executables in App Directory
_getExecutables()

; Read Settings INI Values
$INI_Encode    = IniRead( $SavedSettings , 'H264' , 'Encode' , 'False' )
$INI_Preset    = IniRead( $SavedSettings , 'H264' , 'Preset' , 'Medium' )
$INI_Tuning    = IniRead( $SavedSettings , 'H264' , 'Tuning' , 'Film' )
$INI_Quality_V = IniRead( $SavedSettings , 'H264' , 'Quality', '23' )

$INI_MKV       = IniRead( $SavedSettings , 'Force' , 'MKV'     , 'True' )
$INI_MP4       = IniRead( $SavedSettings , 'Force' , 'MP4'     , 'False' )
$INI_Replace   = IniRead( $SavedSettings , 'Force' , 'Replace' , 'False' )

$INI_Deinterlace = IniRead( $SavedSettings , 'Deinterlace' , 'Value' , 'False' )

$INI_Encoder   = IniRead( $SavedSettings , 'Encoder' , 'Value' , 'x264 8bit' )

$INI_AC3       = IniRead( $SavedSettings , 'Preserve' , 'AC3' , 'False' )
$INI_DTS       = IniRead( $SavedSettings , 'Preserve' , 'DTS' , 'False' )

$INI_Quality_A = IniRead( $SavedSettings , 'Settings' , 'Quality' , '90' )
$INI_Recurse   = IniRead( $SavedSettings , 'Settings' , 'Recurse' , 'False' )
$INI_ShutDown  = IniRead( $SavedSettings , 'Settings' , 'Shutdown', 'False' )

$INI_Pathing   = IniRead( $SavedSettings , 'Last Path' , 'Path' , '' )

; Check INI vs Array's
$INI_Preset    = _CheckGUIArray( $INI_Preset    , $Preset   , 'Medium' )
$INI_Tuning    = _CheckGUIArray( $INI_Tuning    , $Tuning   , 'Film' )
$INI_Quality_V = _CheckGUIArray( $INI_Quality_V , $Quality_V, '23' )
;$INI_Quality_A= _CheckGUIArray( $INI_Quality_A , $Quality_A, '04' ) ; FHGaacEnc
;$INI_Quality_A = _CheckGUIArray( $INI_Quality_A , $Quality_A, '90' ); Qaac
$INI_Quality_A = _CheckGUIArray( $INI_Quality_A , $Quality_A, '02' ) ; LAME

#Region ### START Koda GUI section ###
	$VideoGain = GUICreate("Video Gain - v" & $AppVersion, 388, 288, 342, 343)

	$Force            = GUICtrlCreateGroup("Force", 8, 4, 114, 80)
	$ChkBox_MKV       = GUICtrlCreateCheckbox("MKV", 20, 23, 41, 17)
	$ChkBox_MP4       = GUICtrlCreateCheckbox("MP4", 70, 23, 41, 17)
	$ChkBox_Replace   = GUICtrlCreateCheckbox("Direct Replace", 20, 52, 97, 17)
	GUICtrlCreateGroup("", -99, -99, 1, 1)

	If $INI_MKV       = 'True' Then GUICtrlSetState( $ChkBox_MKV , $GUI_CHECKED )
	If $INI_MP4       = 'True' Then GUICtrlSetState( $ChkBox_MP4 , $GUI_CHECKED )
	If $INI_Replace   = 'True' Then GUICtrlSetState( $ChkBox_Replace , $GUI_CHECKED )

	$H264             = GUICtrlCreateGroup("H264", 132, 4, 245, 80)
	$ChkBox_Encode    = GUICtrlCreateCheckbox("Re - Encode:", 145, 23, 81, 17, BitOR($GUI_SS_DEFAULT_CHECKBOX,$BS_RIGHTBUTTON))
	$Label_Quality    = GUICtrlCreateLabel("Quality:", 144, 54, 39, 17)
	$Combo_Quality    = GUICtrlCreateCombo("", 185, 52, 41, 25, BitOR($CBS_DROPDOWNLIST,$WS_VSCROLL))
		GUICtrlSetData ( -1 , $Quality_V , $INI_Quality_V )
	$Label_Preset     = GUICtrlCreateLabel("Preset:", 245, 25, 37, 17)
	$Combo_Preset     = GUICtrlCreateCombo("", 284, 21, 81, 25, BitOR($CBS_DROPDOWNLIST,$WS_VSCROLL))
		GUICtrlSetData ( -1 , $Preset , $INI_Preset )
	$Label_Tuning     = GUICtrlCreateLabel("Tuning:", 242, 54, 40, 17)
	$Combo_Tuning     = GUICtrlCreateCombo("", 284, 52, 81, 25, BitOR($CBS_DROPDOWNLIST,$WS_VSCROLL))
		GUICtrlSetData ( -1 , $Tuning , $INI_Tuning )
	GUICtrlCreateGroup("", -99, -99, 1, 1)

	If $INI_Encode    = 'True' Then GUICtrlSetState( $ChkBox_Encode , $GUI_CHECKED )

	$Deinterlace      = GUICtrlCreateGroup("Deinterlace", 8, 88, 114, 49)
	$DI_Yes           = GUICtrlCreateRadio("Yes", 20, 107, 41, 17)
	$DI_No            = GUICtrlCreateRadio("No", 70, 107, 41, 17)
	GUICtrlCreateGroup("", -99, -99, 1, 1)

	If $INI_Deinterlace = 'True'  Then GUICtrlSetState( $DI_Yes , $GUI_CHECKED )
	If $INI_Deinterlace = 'False' Then GUICtrlSetState( $DI_No  , $GUI_CHECKED )

	$SelectEncoder    = GUICtrlCreateGroup("Encoder", 132, 88, 245, 49)
	$FFMpeg           = GUICtrlCreateRadio("FFMpeg", 144, 107, 65, 17)
	$x264_8bit        = GUICtrlCreateRadio("x264 8bit", 220, 107, 81, 17)
	$x264_10bit       = GUICtrlCreateRadio("x264 10bit", 300, 107, 65, 17)
	GUICtrlCreateGroup("", -99, -99, 1, 1)

	If $INI_Encoder   = 'FFMpeg'     Then GUICtrlSetState( $FFMpeg    , $GUI_CHECKED )
	If $INI_Encoder   = 'x264 8bit'  Then GUICtrlSetState( $x264_8bit , $GUI_CHECKED )
	If $INI_Encoder   = 'x264 10bit' Then GUICtrlSetState( $x264_10bit, $GUI_CHECKED )

	$Preserve         = GUICtrlCreateGroup("Preserve", 8, 141, 114, 49)
	$ChkBox_AC3       = GUICtrlCreateCheckbox("AC3", 20, 160, 49, 17)
	$ChkBox_DTS       = GUICtrlCreateCheckbox("DTS", 70, 160, 49, 17)
	GUICtrlCreateGroup("", -99, -99, 1, 1)

	If $INI_AC3       = 'True' Then GUICtrlSetState( $ChkBox_AC3 , $GUI_CHECKED )
	If $INI_DTS       = 'True' Then GUICtrlSetState( $ChkBox_DTS , $GUI_CHECKED )

	$Settings         = GUICtrlCreateGroup("Settings", 132, 141, 245, 49)
	$Label_Audio      = GUICtrlCreateLabel("Audio Quality:", 144, 162, 69, 17)
	$Combo_Audio      = GUICtrlCreateCombo("", 215, 158, 41, 25, BitOR($CBS_DROPDOWNLIST,$WS_VSCROLL))
		GUICtrlSetData ( -1 , $Quality_A , $INI_Quality_A )
	$ChkBox_Recurse   = GUICtrlCreateCheckbox("Recurse Folders:", 260, 160, 105, 17, BitOR($GUI_SS_DEFAULT_CHECKBOX,$BS_RIGHTBUTTON,$BS_RIGHT))
	GUICtrlCreateGroup("", -99, -99, 1, 1)

	If $INI_Recurse   = 'True' Then GUICtrlSetState( $ChkBox_Recurse , $GUI_CHECKED )

	$Input_FolderPath = GUICtrlCreateInput("", 8, 200, 347, 21)
	$Button_FolderPath= GUICtrlCreateButton("...", 355, 199, 23, 23)

	If FileExists( $INI_Pathing ) Then GUICtrlSetData( $Input_FolderPath , $INI_Pathing )

	$Process          = GUICtrlCreateGroup("", 8, 225, 369, 51)
	$ChkBox_Shutdown  = GUICtrlCreateCheckbox("Shutdown when finished.", 20, 245, 145, 17)
	$Button_Exit      = GUICtrlCreateButton("Exit", 211, 241, 75, 25)
	$Button_Run       = GUICtrlCreateButton("Run", 291, 241, 75, 25)
	GUICtrlCreateGroup("", -99, -99, 1, 1)

	If $INI_ShutDown  = 'True' Then GUICtrlSetState( $ChkBox_Shutdown , $GUI_CHECKED )

	GUISetState(@SW_SHOW)
#EndRegion ### END Koda GUI section ###

#Region ### START Koda GUI section ###
	$Progress = GUICreate("Video Gain - Progress", 413, 260, 365, 601 )
	GUISetOnEvent( $GUI_EVENT_CLOSE    , "_Exit" , $Progress )
	GUISetOnEvent( $GUI_EVENT_MINIMIZE , "_Hide" , $Progress )

	$Progress_Group_1 = GUICtrlCreateGroup(" Over All ", 8, 8, 393, 57)
	$Progress_1       = GUICtrlCreateProgress(16, 32, 374, 17)
	GUICtrlCreateGroup("", -99, -99, 1, 1)

	$Progress_Group_2 = GUICtrlCreateGroup(" Current File ", 8, 77, 393, 57)
	$Progress_2       = GUICtrlCreateProgress(16, 101, 374, 17)
	GUICtrlCreateGroup("", -99, -99, 1, 1)

	$Progress_Group_3 = GUICtrlCreateGroup(" Current Stream ", 8, 144, 393, 57)
	$Progress_3       = GUICtrlCreateProgress(16, 168, 374, 17)
	GUICtrlCreateGroup("", -99, -99, 1, 1)

	$Label_Process    = GUICtrlCreateLabel("Processing :", 8, 212, 62, 17)
	$Label_Processing = GUICtrlCreateLabel("", 72, 212, 244, 17)

	$Progress_Exit    = GUICtrlCreateButton("&Exit", 326, 208, 75, 25)
	GUICtrlSetOnEvent( $Progress_Exit , "_Exit" )
	$Progress_StatusBar = _GUICtrlStatusBar_Create($Progress)
	_GUICtrlStatusBar_SetText($Progress_StatusBar, "")
	GUISetState(@SW_HIDE)
#EndRegion ### END Koda GUI section ###

While 1
	$Msg = GUIGetMsg()
	Switch $Msg
		Case $GUI_EVENT_CLOSE
			_Close()
		Case $Button_Exit
			_WriteSettings()
			_Close()
		Case $GUI_EVENT_MINIMIZE
			$Show_String = $VideoGain
			GUISetState( @SW_HIDE , $Show_String )
			TraySetState(1)
		Case $ChkBox_MKV
			_Toggle_CheckBox( $VideoGain , $ChkBox_MKV , $ChkBox_MP4 )
		Case $ChkBox_MP4
			_Toggle_CheckBox( $VideoGain , $ChkBox_MP4 , $ChkBox_MKV )
		Case $Button_FolderPath
			$CurrentPath = GUICtrlRead( $Input_FolderPath )
			If NOT FileExists( $CurrentPath ) Then
				$CurrentPath = ''
			EndIf
			$Folder = FileSelectFolder( 'Select Video Folder.' , '' , 2 , $CurrentPath )
			If NOT @Error Then
				If StringRight( $Folder , 1 ) <> '\' Then $Folder &= '\'
				GUICtrlSetData( $Input_FolderPath , $Folder )
			EndIf
		Case $Button_Run
			$Videos = GUICtrlRead( $Input_FolderPath )
			If FileExists( $Videos ) Then
				If StringRight( $Videos , 1 ) <> '\' Then $Videos &= '\'
				Global $AllFiles = _FileListToArrayXT( $Videos , $Extensions , 1 , 2 , _getControlBoolValue( $ChkBox_Recurse ) , '' , 1 )
				If IsArray( $AllFiles ) <> 1 Then
					MsgBox( 4096 , 'Error:' , 'No Video Files Found!' )
				Else
					_WriteSettings()
					GUISetState( @SW_HIDE , $VideoGain )
					GUISetState( @SW_SHOW , $Progress )
					$Show_String = ''
					Opt( 'GUIOnEventMode'  , 1 )
					_Main()
					Opt( 'GUIOnEventMode'  , 0 )
					$Show_String = ''
					GUISetState( @SW_HIDE , $Progress )
					GUISetState( @SW_SHOW , $VideoGain )
					TraySetState( 2 )
				EndIf
				Global $AllFiles = ''
			Else
				MsgBox( 4096 , 'Error:' , 'Invalid Path given.' )
			EndIf
	EndSwitch
WEnd

;   //////////////////////////////////////////////////////////////////////////////////////////////////////////////
;  // Main Function
; //////////////////////////////////////////////////////////////////////////////////////////////////////////////

Func _Main()
	$Quality  = GUICtrlRead( $Combo_Audio )
	$AC3      = _getControlBoolValue( $ChkBox_AC3 )
	$DTS      = _getControlBoolValue( $ChkBox_DTS )
	$Shutdown = _getControlBoolValue( $ChkBox_Shutdown )
	$Replace  = _getControlBoolValue( $ChkBox_Replace )
	$ReEncode = _getControlBoolValue( $ChkBox_Encode )
	$Delace   = _getControlBoolValue( $DI_Yes )
	If GUICtrlRead( $FFMpeg    ) = 1 Then $Encoder = 'FFMpeg'
	If GUICtrlRead( $x264_8bit ) = 1 Then $Encoder = 'x264 8bit'
	If GUICtrlRead( $x264_10bit) = 1 Then $Encoder = 'x264 10bit'
	$CRF     = GUICtrlRead( $Combo_Quality )
	$Preset  = GUICtrlRead( $Combo_Preset )
	$Tuning  = GUICtrlRead( $Combo_Tuning )
	$FinalExt = ''
	If _getControlBoolValue( $ChkBox_MKV ) = True Then $GUIFinalExt = '.mkv'
	If _getControlBoolValue( $ChkBox_MP4 ) = True Then $GUIFinalExt = '.mp4'

	; Create Temp Folder
	$TempFolder = @TempDir & '\Video Gain\'
	If NOT FileExists( $TempFolder ) Then DirCreate( $TempFolder )

	; Start Timer
	$Initial_Time = TimerInit()

	; Counters
	$Count_Files  = $AllFiles[0]
	$Count_Errors = 0

	For $i = 1 To $AllFiles[0]
		; Test If File Still Exists
		If NOT FileExists( $AllFiles[$i] ) Then
			$Count_Files -= 1
			ContinueLoop
		EndIf

		; Remove Junk In Temp Folder
		_RemoveJunk()

		; Clear Strings
		$String_AVI_File = ''
		$String_MKV_File = ''
		$String_MP4_File = ''

		; Define Macro's
		$RootTemp   = StringLeft      ( $TempFolder   , StringInStr ( $TempFolder   , '\' , 0 ) )
		$Root       = StringLeft      ( $AllFiles[$i] , StringInStr ( $AllFiles[$i] , '\' , 0 ) )
		$FileDir    = StringLeft      ( $AllFiles[$i] , StringInStr ( $AllFiles[$i] , '\' , 0 , -1 ) )
		$FileExt    = StringTrimLeft  ( $AllFiles[$i] , StringInStr ( $AllFiles[$i] , '.' , 0 , -1 ) - 1 )
		$FileName   = StringTrimLeft  ( $AllFiles[$i] , StringInStr ( $AllFiles[$i] , '\' , 0 , -1 ) )
		$ShortName  = StringLeft      ( $FileName     , StringInStr ( $FileName     , '.' , 0 , -1 ) - 1 )
		$Parent     = StringTrimLeft  ( $FileDir      , StringInStr ( $FileDir      , '\' , 0 , -2 ) )
		$Complete   = $FileDir & 'Complete\'
		$FinalExt   = $FileExt

		; Check For Enough Hard Drive Space
		$SpaceRootTemp  = Int( DriveSpaceFree( $RootTemp ))
		$SpaceRoot      = Int( DriveSpaceFree( $Root     ))
		$ActiveFileSize = Int( Mod( FileGetSize( $AllFiles[$i] ) , 1073741824 ) / 1048576 )
		If $Replace = False AND $Root = $RootTemp Then
			If $SpaceRoot < ( $ActiveFileSize * 2 ) Then
				_NotEnoughSpaceError( $AllFiles[$i] , $Root )
				ContinueLoop
			EndIf
		Else
			If $SpaceRootTemp < ( $ActiveFileSize ) Then
				_NotEnoughSpaceError( $AllFiles[$i] , $RootTemp )
				ContinueLoop
			EndIf
			If $Replace = True  AND $SpaceRoot < ( $ActiveFileSize ) Then
				_NotEnoughSpaceError( $AllFiles[$i] , $Root )
				ContinueLoop
			EndIf
			If $Replace = False AND $SpaceRoot < ( $ActiveFileSize * 2 ) Then
				_NotEnoughSpaceError( $AllFiles[$i] , $Root )
				ContinueLoop
			EndIf
		EndIf

		; Test Final Video Container #1
		If $FinalExt = '.avs' Then $FinalExt = '.mkv'

		; Test Final Video Container #2
		If $GUIFinalExt <> '' Then $FinalExt = $GUIFinalExt

		; Skip if in Complete Folder
		If $Replace = False AND StringInStr( $AllFiles[$i] , 'Complete\' ) <> 0 Then ContinueLoop

		; Skip if Already Completed
		If $Replace = False AND FileExists ( $Complete & $ShortName & '.*' ) Then ContinueLoop

		; Update Progress Processing Label
		GUICtrlSetData( $Label_Processing , $ShortName )

		; Display TrayTip
		If BitAND( WinGetState( $Progress ) , 2 ) <> 2 Then TrayTip( '' , 'Processing #' & $i & ' of ' & $AllFiles[0] & @LF & 'Video: ' & $ShortName , 10 , 16 )

		; Change Progress Title
		WinSetTitle( $Progress , '' , 'Video Gain - Progress (' & $i & ' of ' & $AllFiles[0] & ')' )

		; Global File Count
		$File_Count = $i - 1

		; Set Active File Count
		Dim $Active_File_Count[1] = [0]

		; Build Active File Array
		$File_Array = ''

		; Grab Stream Output
		$Output = ''
		$Read = Run( @ComSpec & ' /c ffprobe.exe -show_streams "' & $AllFiles[$i] & '"' , @ScriptDir & '\BIN\FFMpeg\' , @SW_HIDE , $STDOUT_CHILD )
		While 1
			$Output &= StdoutRead( $Read )
			If @Error Then ExitLoop
		WEnd

		; Build Array of Streams
		$Streams_All = _StringBetween( $Output , '[STREAM]' , '[/STREAM]' )

		; Create Stream Count
		$Stream_Count = 0

		; Create Stream Count for All Streams
		$Streams_Count_All = UBound( $Streams_All ) + 2

		; Define Count & Content For Video Streams
		$Streams_Find = _ArrayFindAll( $Streams_All , 'codec_type=video' , 0 , 0 , 0 , 1 )
		If $Streams_Find = -1 Then
			Dim $Streams_Video[1] = [0]
		Else
			Dim $Streams_Video[1] = [UBound( $Streams_Find )]
			For $a = 0 To UBound( $Streams_Find ) - 1
				_ArrayAdd( $Streams_Video , $Streams_All[$Streams_Find[$a]] )
			Next
			; Build Array Based on FFProbe Info
			For $a = 1 To $Streams_Video[0]
				Global $Array_Video[15][2]=[[' 0 Index'                        ] , _
													[ ' 1 Codec Name'                   ] , _
													[ ' 2 Width'                        ] , _
													[ ' 3 Height'                       ] , _
													[ ' 4 Sample Aspect Ratio'          ] , _
													[ ' 5 Display Aspect Ratio'         ] , _
													[ ' 6 Pixel Format'                 ] , _
													[ ' 7 Render Frame Rate Numerator'  ] , _
													[ ' 8 Render Frame Rate Denominator'] , _
													[ ' 9 Language'                     ] , _
													[ '10 Start Time'                   ] , _
													[ '11 Duration'                     ] , _
													[ '12 Lang Meta'                    ] , _
													[ '13 Name Meta'                    ] , _
													[ '14 Number of Frames'             ] ]

				$Array_Video[0][1]  = _RegExString( $Streams_Video[$a] , '(?s)(?i)(?:.+?index=(\S+))?'                ) ;  0 Index
				$Array_Video[1][1]  = _RegExString( $Streams_Video[$a] , '(?s)(?i)(?:.+?codec_name=(\S+))?'           ) ;  1 Codec Name
				$Array_Video[2][1]  = _RegExString( $Streams_Video[$a] , '(?s)(?i)(?:.+?width=(\S+))?'                ) ;  2 Width
				$Array_Video[3][1]  = _RegExString( $Streams_Video[$a] , '(?s)(?i)(?:.+?height=(\S+))?'               ) ;  3 Height
				$Array_Video[4][1]  = _RegExString( $Streams_Video[$a] , '(?s)(?i)(?:.+?sample_aspect_ratio=(\S+))?'  ) ;  4 Sample Aspect Ratio
				$Array_Video[5][1]  = _RegExString( $Streams_Video[$a] , '(?s)(?i)(?:.+?display_aspect_ratio=(\S+))?' ) ;  5 Display Aspect Ratio
				$Array_Video[6][1]  = _RegExString( $Streams_Video[$a] , '(?s)(?i)(?:.+?pix_fmt=(\S+))?'              ) ;  6 Pixel Format
				$Array_Video[7][1]  = _RegExString( $Streams_Video[$a] , '(?s)(?i)(?:.+?r_frame_rate=(\d+)/)?'        ) ;  7 Render Frame Rate Numerator
				$Array_Video[8][1]  = _RegExString( $Streams_Video[$a] , '(?s)(?i)(?:.+?r_frame_rate=\d+/(\d+))?'     ) ;  8 Render Frame Rate Denominator
				$Array_Video[9][1]  = _RegExString( $Streams_Video[$a] , '(?s)(?i)(?:.+?language=(\S+))?'             ) ;  9 Language
				$Array_Video[10][1] = _RegExString( $Streams_Video[$a] , '(?s)(?i)(?:.+?start_time=(\S+))?'           ) ; 10 Start Time
				$Array_Video[11][1] = _RegExString( $Streams_Video[$a] , '(?s)(?i)(?:.+?duration=(\S+))?'             ) ; 11 Duration
				$Array_Video[12][1] = _RegExString( $Streams_Video[$a] , '(?s)(?i)(?:.+?TAG:language=(\S+))?'         ) ; 12 Lang Meta
				$Array_Video[13][1] = _RegExString( $Streams_Video[$a] , '(?s)(?i)(?:.+?TAG:title=(\V+))?'            ) ; 13 Name Meta
				$Array_Video[14][1] = _RegExString( $Streams_Video[$a] , '(?s)(?i)(?:.+?nb_frames=(\S+))?'            ) ; 14 Number of Frames
;           _ArrayDisplay( $Array_Video )

				; Double Index Count
				If StringLen( $a ) = 1 Then $Double_Count = '0' & $a
				If StringLen( $a ) = 2 Then $Double_Count = $a

				; Set AVI Meta
				$AVI_Meta = ''
				If $Array_Video[9][1]  <> '' Then $AVI_Meta &= ' -vlang "'             & $Array_Video[9][1]  & '"'
				If $Array_Video[12][1] <> '' Then $AVI_Meta &= ' -metadata language="' & $Array_Video[12][1] & '"'
				If $Array_Video[12][1] <> '' Then $AVI_Meta &= ' -metadata title="'    & $Array_Video[13][1] & '"'

				; Set MKV Meta
				$MKV_Meta = ''
				If $Array_Video[9][1]  <> '' Then $MKV_Meta &= ' --language 0:"'   & $Array_Video[9][1]  & '"'
				If $Array_Video[13][1] <> '' Then $MKV_Meta &= ' --track-name 0:"' & $Array_Video[13][1] & '"'

				; Set MP4 Meta
				$MP4_Meta = ''
				If $Array_Video[9][1]  <> '' Then $MP4_Meta &= ':lang="' & $Array_Video[9][1]  & '"'
				If $Array_Video[13][1] <> '' Then $MP4_Meta &= ':name="' & $Array_Video[13][1] & '"'

				; Deinterlace
				$Deinterlace = ''
				If $Delace = True Then $Deinterlace = ' -deinterlace'

				; Update Current Stream Progress
				GUICtrlSetData( $Progress_3 , 0 )

				; Decide to Re-Encode or Not
				If $Array_Video[1][1] <> 'h264' AND $ReEncode = True Then
					Switch $Encoder
						Case 'x264 8bit'
							$Stream_PID = Run( @ComSpec & ' /c .\FFMpeg\ffmpeg.exe -i "' & $AllFiles[$i] & '" -map 0:' & $Array_Video[0][1] & ' -c rawvideo -f rawvideo' & $Deinterlace & ' - | .\x264\x264-8bit.exe --tune ' & $Tuning & ' --crf ' & $CRF & ' --preset ' & $Preset & ' --fps ' & $Array_Video[7][1] / $Array_Video[8][1] & ' --input-res ' & $Array_Video[2][1] & 'x' & $Array_Video[3][1] & ' --output "' & $TempFolder & 'Video_' & $Double_Count & '.mp4" -' , @ScriptDir & '\BIN\' , @SW_HIDE , $STDERR_CHILD + $STDOUT_CHILD )
						Case 'x264 10bit'
							$Stream_PID = Run( @ComSpec & ' /c .\FFMpeg\ffmpeg.exe -i "' & $AllFiles[$i] & '" -map 0:' & $Array_Video[0][1] & ' -c rawvideo -f rawvideo' & $Deinterlace & ' - | .\x264\x264-10bit.exe --tune ' & $Tuning & ' --crf ' & $CRF & ' --preset ' & $Preset & ' --fps ' & $Array_Video[7][1] / $Array_Video[8][1] & ' --input-res ' & $Array_Video[2][1] & 'x' & $Array_Video[3][1] & ' --output "' & $TempFolder & 'Video_' & $Double_Count & '.mp4" -' , @ScriptDir & '\BIN\' , @SW_HIDE , $STDERR_CHILD + $STDOUT_CHILD )
						Case Else
							$Stream_PID = Run( @ComSpec & ' /c ffmpeg.exe -i "' & $AllFiles[$i] & '" -map 0:' & $Array_Video[0][1] & ' -c:v libx264 -tune ' & $Tuning & ' -crf ' & $CRF & ' -preset ' & $Preset & $Deinterlace & ' "' & $TempFolder & 'Video_' & $Double_Count & '.mp4"' , @ScriptDir & '\BIN\FFMpeg\' , @SW_HIDE , $STDERR_CHILD + $STDOUT_CHILD )
					EndSwitch
					; Test Container Extension
					If $FinalExt <> '.avi' AND $FinalExt <> '.f4v' AND $FinalExt <> '.m4v' AND $FinalExt <> '.mkv' AND $FinalExt <> '.mp4' Then $FinalExt = '.mkv'
					; Update Statusbar
					_GUICtrlStatusBar_SetText( $Progress_StatusBar , '  Encoding Video Stream ' & $a & ' of ' & $Streams_Video[0] )
				Else
					$Stream_PID = Run( @ComSpec & ' /c ffmpeg.exe -i "' & $AllFiles[$i] & '" -map 0:' & $Array_Video[0][1] & ' -c copy -y "' & $TempFolder & 'Video_' & $Double_Count & '.mp4"' , @ScriptDir & '\BIN\FFMpeg\' , @SW_HIDE , $STDERR_CHILD + $STDOUT_CHILD )
					; Update Statusbar
					_GUICtrlStatusBar_SetText( $Progress_StatusBar , '  Copying Video Stream ' & $a & ' of ' & $Streams_Video[0] )
				EndIf

				; Update Current Stream Progress
				Dim $Stream_Feed
				While 1
					$Stream_Feed = StderrRead( $Stream_PID )
					If @Error Then ExitLoop
					If StringInStr( $Stream_Feed , 'frame=' ) Then
						$Feed_Count = StringRegExp( $Stream_Feed , '(?i)frame=\h*(\H+)\h' , 3 )
						If IsArray( $Feed_Count ) Then
							$Precent_1 = ( $Feed_Count[UBound( $Feed_Count ) - 1] / $Array_Video[14][1] ) * 100
							$Precent_2 = ((( $Precent_1 / 100 ) / $Streams_Count_All ) + ( $Stream_Count / $Streams_Count_All )) * 100
							$Precent_3 = ((( $Precent_2 / 100 ) / $Count_Files ) + ( $File_Count / $Count_Files )) * 100
							_UpdateProgress()
						EndIf
					EndIf
					Sleep( 10 )
				WEnd

				; Set Strings
				$String_AVI_File &= ' -i ' & FileGetShortName( $TempFolder & 'Video_' & $Double_Count & '.mp4' ) & $AVI_Meta
				$String_MKV_File &= ' -d 0 -A -S -T' & $MKV_Meta & ' "' & $TempFolder & 'Video_' & $Double_Count & '.mp4' & '"'
				$String_MP4_File &= ' -add ' & FileGetShortName( $TempFolder & 'Video_' & $Double_Count & '.mp4' ) & ':fps=' & $Array_Video[7][1] / $Array_Video[8][1] & $MP4_Meta

				; Increase Active File Count
				$Active_File_Count[0] += 1

				; Add File to File Count
				_ArrayAdd( $Active_File_Count , 'Video_' & $Double_Count & '.mp4' )

				; Test If File Was Actually Created
				If NOT FileExists( $TempFolder & 'Video_' & $Double_Count & '.mp4' ) OR FileGetSize( $TempFolder & 'Video_' & $Double_Count & '.mp4' ) < 10240 Then
					$ErrorLog &= 'Failed to Create Video Stream ' & $Double_Count & ' For:' & @CRLF & $AllFiles[$i] & @CRLF & @CRLF
					$Count_Errors += 1
					ContinueLoop 2
				EndIf

				; Update Current File Progress
				$Stream_Count += 1
			Next
		EndIf

		; Define Count & Content For Audio Streams
		$Streams_Find = _ArrayFindAll( $Streams_All , 'codec_type=audio' , 0 , 0 , 0 , 1 )
		If $Streams_Find = -1 Then
			Dim $Streams_Audio[1] = [0]
		Else
			Dim $Streams_Audio[1] = [UBound( $Streams_Find )]
			For $a = 0 To UBound( $Streams_Find ) - 1
				_ArrayAdd( $Streams_Audio , $Streams_All[$Streams_Find[$a]] )
			Next
			; Build Array Based on FFProbe Info
			For $a = 1 To $Streams_Audio[0]
				Global $Array_Audio[9][2]=[[ '0 Index'       ] , _
													[ '1 Codec Name'  ] , _
													[ '2 Sample Rate' ] , _
													[ '3 Channels'    ] , _
													[ '4 Language'    ] , _
													[ '5 Start Time'  ] , _
													[ '6 Duration'    ] , _
													[ '7 Lang Meta'   ] , _
													[ '8 Name Meta'   ] ]

				$Array_Audio[0][1] = _RegExString( $Streams_Audio[$a] , '(?s)(?i)(?:.+?index=(\S+))?'        ) ; 0 Index
				$Array_Audio[1][1] = _RegExString( $Streams_Audio[$a] , '(?s)(?i)(?:.+?codec_name=(\S+))?'   ) ; 1 Codec Name
				$Array_Audio[2][1] = _RegExString( $Streams_Audio[$a] , '(?s)(?i)(?:.+?sample_rate=(\S+))?'  ) ; 2 Sample Rate
				$Array_Audio[3][1] = _RegExString( $Streams_Audio[$a] , '(?s)(?i)(?:.+?channels=(\S+))?'     ) ; 3 Number Of Channels
				$Array_Audio[4][1] = _RegExString( $Streams_Audio[$a] , '(?s)(?i)(?:.+?language=(\S+))?'     ) ; 4 Language
				$Array_Audio[5][1] = _RegExString( $Streams_Audio[$a] , '(?s)(?i)(?:.+?start_time=(\S+))?'   ) ; 5 Start Time
				$Array_Audio[6][1] = _RegExString( $Streams_Audio[$a] , '(?s)(?i)(?:.+?duration=(\S+))?'     ) ; 6 Duration
				$Array_Audio[7][1] = _RegExString( $Streams_Audio[$a] , '(?s)(?i)(?:.+?TAG:language=(\S+))?' ) ; 7 Lang Meta
				$Array_Audio[8][1] = _RegExString( $Streams_Audio[$a] , '(?s)(?i)(?:.+?TAG:title=(\V+))?'    ) ; 8 Name Meta
;           _ArrayDisplay( $Array_Audio )

				; Double Index Count
				If StringLen( $a ) = 1 Then $Double_Count = '0' & $a
				If StringLen( $a ) = 2 Then $Double_Count = $a

				; Set AVI Meta
				$AVI_Meta = ''
				If $Array_Audio[4][1] <> '' Then $AVI_Meta &= ' -alang "'             & $Array_Audio[4][1]   & '"'
				If $Array_Audio[7][1] <> '' Then $AVI_Meta &= ' -metadata language="' & $Array_Audio[7][1]   & '"'
				If $Array_Audio[8][1] <> '' Then $AVI_Meta &= ' -metadata title="'    & $Array_Audio[8][1]   & '"'

				; Set MKV Meta
				$MKV_Meta = ''
				If $Array_Audio[4][1] <> '' Then $MKV_Meta &= ' --language 0:"'   & $Array_Audio[4][1] & '"'
				If $Array_Audio[8][1] <> '' Then $MKV_Meta &= ' --track-name 0:"' & $Array_Audio[8][1] & '"'

				; Set Meta
				$MP4_Meta = ''
				If $Array_Audio[4][1] <> '' Then $MP4_Meta &= ':lang="' & $Array_Audio[4][1]  & '"'
				If $Array_Audio[8][1] <> '' Then $MP4_Meta &= ':name="' & $Array_Audio[8][1]  & '"'

				; Update Current Stream Progress
				GUICtrlSetData( $Progress_3 , 0 )

				; Set Audio Extension
				Select
					Case $Array_Audio[1][1] = 'MP3'
						$Audio_Ext = '.mp3'
						_GUICtrlStatusBar_SetText( $Progress_StatusBar , '  Copying Audio Stream ' & $a & ' of ' & $Streams_Audio[0] )
						_Sound  ( $AllFiles[$i] , $TempFolder & 'Audio_' & $Double_Count & $Audio_Ext , $Array_Audio[0][1] , 2 )
						_GUICtrlStatusBar_SetText( $Progress_StatusBar , '  Normalize Audio Stream ' & $a & ' of ' & $Streams_Audio[0] )
						_AACGain( $TempFolder & 'Audio_' & $Double_Count & $Audio_Ext )
						$Index_A = 0
					Case $Array_Audio[1][1] = 'AAC'
						$Audio_Ext = '.mp4'
						_GUICtrlStatusBar_SetText( $Progress_StatusBar , '  Copying Audio Stream ' & $a & ' of ' & $Streams_Audio[0] )
						_Sound  ( $AllFiles[$i] , $TempFolder & 'Audio_' & $Double_Count & $Audio_Ext , $Array_Audio[0][1] , 2 )
						_GUICtrlStatusBar_SetText( $Progress_StatusBar , '  Normalize Audio Stream ' & $a & ' of ' & $Streams_Audio[0] )
						_AACGain( $TempFolder & 'Audio_' & $Double_Count & $Audio_Ext )
						$Index_A = 1
					Case $Array_Audio[1][1] = 'AC3' AND $AC3 = True
						$Audio_Ext = '.ac3'
						_GUICtrlStatusBar_SetText( $Progress_StatusBar , '  Copying Audio Stream ' & $a & ' of ' & $Streams_Audio[0] )
						_Sound  ( $AllFiles[$i] , $TempFolder & 'Audio_' & $Double_Count & $Audio_Ext , $Array_Audio[0][1] , 1 )
						$Index_A = 0
					Case $Array_Audio[1][1] = 'DCA' AND $DTS = True
						$Audio_Ext = '.dts'
						_GUICtrlStatusBar_SetText( $Progress_StatusBar , '  Copying Audio Stream ' & $a & ' of ' & $Streams_Audio[0] )
						_Sound  ( $AllFiles[$i] , $TempFolder & 'Audio_' & $Double_Count & $Audio_Ext , $Array_Audio[0][1] , 1 )
						$Index_A = 0
					Case Else
						$Audio_Ext = '.mp3'
						_GUICtrlStatusBar_SetText( $Progress_StatusBar , '  Encoding Audio Stream ' & $a & ' of ' & $Streams_Audio[0] )
						_Convert( $AllFiles[$i] , $TempFolder & 'Audio_' & $Double_Count & $Audio_Ext , $Array_Audio[0][1] )
						_GUICtrlStatusBar_SetText( $Progress_StatusBar , '  Normalize Audio Stream ' & $a & ' of ' & $Streams_Audio[0] )
						_AACGain( $TempFolder & 'Audio_' & $Double_Count & $Audio_Ext )
						$Index_A = 1
				EndSelect

				; Test Audio Extension VS. Container Extension
				If $Audio_Ext = '.mp4' AND $Streams_Video[0] > 0 AND $FinalExt <> '.f4v' AND $FinalExt <> '.m4v' AND $FinalExt <> '.mkv' AND $FinalExt <> '.mp4' Then $FinalExt = '.mkv'
				If $Audio_Ext = '.mp4' AND $Streams_Video[0] = 0 AND $FinalExt <> '.f4v' AND $FinalExt <> '.m4a' AND $FinalExt <> '.mkv' AND $FinalExt <> '.mp4' Then $FinalExt = '.m4a'

				; Set Strings
				$String_AVI_File &= ' -i ' & FileGetShortName( $TempFolder & 'Audio_' & $Double_Count & $Audio_Ext ) & $AVI_Meta
				$String_MKV_File &= ' -a 0 -D -S -T' & $MKV_Meta & ' "' & $TempFolder & 'Audio_' & $Double_Count & $Audio_Ext & '"'
				$String_MP4_File &= ' -add ' & FileGetShortName( $TempFolder & 'Audio_' & $Double_Count & $Audio_Ext ) & $MP4_Meta

				; Increase Active File Count
				$Active_File_Count[0] += 1

				; Add File to File Count
				_ArrayAdd( $Active_File_Count , 'Audio_' & $Double_Count & $Audio_Ext )

				; Test If File Was Actually Created
				If NOT FileExists( $TempFolder & 'Audio_' & $Double_Count & $Audio_Ext ) OR FileGetSize( $TempFolder & 'Audio_' & $Double_Count & $Audio_Ext ) < 2048 Then
					$ErrorLog &= 'Failed to Create Audio Stream ' & $Double_Count & ' For:' & @CRLF & $AllFiles[$i] & @CRLF & @CRLF
					$Count_Errors += 1
					ContinueLoop 2
				EndIf

				; Update Current File Progress
				$Stream_Count += 1
			Next
		EndIf

		; Define Count & Content For SubTitle Streams
		$Streams_Find = _ArrayFindAll( $Streams_All , 'codec_type=subtitle' , 0 , 0 , 0 , 1 )
		If $Streams_Find = -1 Then
			Dim $Streams_Subs[1] = [0]
		Else
			Dim $Streams_Subs[1] = [UBound( $Streams_Find )]
			For $a = 0 To UBound( $Streams_Find ) - 1
				_ArrayAdd( $Streams_Subs , $Streams_All[$Streams_Find[$a]] )
			Next
			; Build Array Based on FFProbe Info
			For $a = 1 To $Streams_Subs[0]
				Global $Array_Subs[7][2]=[ [ '0 Index'       ] , _
													[ '1 Codec Name'  ] , _
													[ '2 Language'    ] , _
													[ '3 Start Time'  ] , _
													[ '4 Duration'    ] , _
													[ '5 Lang Meta'   ] , _
													[ '6 Name Meta'   ] ]

				$Array_Subs[0][1] = _RegExString( $Streams_Subs[$a] , '(?s)(?i)(?:.+?index=(\S+))?'        ) ; 1 Index
				$Array_Subs[1][1] = _RegExString( $Streams_Subs[$a] , '(?s)(?i)(?:.+?codec_name=(\S+))?'   ) ; 2 Codec Name
				$Array_Subs[2][1] = _RegExString( $Streams_Subs[$a] , '(?s)(?i)(?:.+?language=(\S+))?'     ) ; 3 Language
				$Array_Subs[3][1] = _RegExString( $Streams_Subs[$a] , '(?s)(?i)(?:.+?start_time=(\S+))?'   ) ; 4 Start Time
				$Array_Subs[4][1] = _RegExString( $Streams_Subs[$a] , '(?s)(?i)(?:.+?duration=(\S+))?'     ) ; 5 Duration
				$Array_Subs[5][1] = _RegExString( $Streams_Subs[$a] , '(?s)(?i)(?:.+?TAG:language=(\S+))?' ) ; 6 Lang Meta
				$Array_Subs[6][1] = _RegExString( $Streams_Subs[$a] , '(?s)(?i)(?:.+?TAG:title=(\V+))?'    ) ; 7 Name Meta
;           _ArrayDisplay( $Array_Subs )

				; Double Index Count
				If StringLen( $a ) = 1 Then $Double_Count = '0' & $a
				If StringLen( $a ) = 2 Then $Double_Count = $a

				; Set AVI Meta
				$AVI_Meta = ''
				If $Array_Subs[2][1] <> '' Then $AVI_Meta &= ' -slang "'             & $Array_Subs[2][1]  & '"'
				If $Array_Subs[5][1] <> '' Then $AVI_Meta &= ' -metadata language="' & $Array_Subs[5][1]  & '"'
				If $Array_Subs[6][1] <> '' Then $AVI_Meta &= ' -metadata title="'    & $Array_Subs[6][1]  & '"'

				; Set MKV Meta
				$MKV_Meta = ''
				If $Array_Subs[2][1] <> '' Then $MKV_Meta &= ' --language 0:"'   & $Array_Subs[2][1]   & '"'
				If $Array_Subs[6][1] <> '' Then $MKV_Meta &= ' --track-name 0":' & $Array_Subs[6][1]   & '"'

				; Set Meta
				$MP4_Meta = ''
				If $Array_Subs[2][1] <> '' Then $MP4_Meta &= ':lang="' & $Array_Subs[2][1] & '"'
				If $Array_Subs[6][1] <> '' Then $MP4_Meta &= ':name="' & $Array_Subs[6][1] & '"'

				; Update Current Stream Progress
				GUICtrlSetData( $Progress_3 , 0 )

				; Handle Sub Codec's
				Select
					Case $Array_Subs[1][1] = 'ASS' OR $Array_Subs[1][1] = 'S_TEXT/SSA' OR $Array_Subs[1][1] = 'S_TEXT/ASS'
						$Sub_Ext = '.ass'
						RunWait( @ComSpec & ' /c ffmpeg.exe -i "' & $AllFiles[$i] & '" -map 0:' & $Array_Subs[0][1] & ' -c copy -y "' & $TempFolder & 'Sub_' & $Double_Count & '.ass"' , @ScriptDir & '\BIN\FFMpeg\' , @SW_HIDE )
						RunWait( @ComSpec & ' /c SubtitleWorkshop.exe "/CONVERT(' & $TempFolder & 'Sub_' & $Double_Count & '.ass/' & $TempFolder & 'Sub_' & $Double_Count & '.srt/SubRip/0/0)"' , @ScriptDir & '\BIN\Subtitle Workshop\' , @SW_HIDE )
					Case $Array_Subs[1][1] = 'SRT' OR $Array_Subs[1][1] = 'S_TEXT/UTF8'
						$Sub_Ext = '.srt'
						RunWait( @ComSpec & ' /c ffmpeg.exe -i "' & $AllFiles[$i] & '" -map 0:' & $Array_Subs[0][1] & ' -c copy -y "' & $TempFolder & 'Sub_' & $Double_Count & '.srt"' , @ScriptDir & '\BIN\FFMpeg\' , @SW_HIDE )
					Case Else
						$Sub_Ext = '.srt'
						Select
							Case $FileExt = '.mkv'
								RunWait( @ComSpec & ' /c mkvextract.exe tracks "' & $AllFiles[$i] & '" ' & $Array_Subs[0][1] + 1 & ':"' & $TempFolder & 'Sub_' & $Double_Count & '.srt"' , @ScriptDir & '\BIN\MKVToolNix\' , @SW_HIDE )
							Case $FileExt = '.mp4' OR $FileExt = '.m4v' OR $FileExt = '.f4v'
								RunWait( @ComSpec & ' /c MP4Box.exe -srt ' & $Array_Subs[0][1] + 1 & ' "' & $AllFiles[$i] & '"' , @ScriptDir & '\BIN\MMP4Box\' , @SW_HIDE )
								FileMove( $FileDir & $ShortName & '_' & $Array_Subs[0][1] + 1 & '_text.srt' , $TempFolder & 'Sub_' & $Double_Count & '.srt' , 9 )
						EndSelect
				EndSelect

				; Set Strings
				$String_AVI_File &= ' -i ' & FileGetShortName( $TempFolder & 'Sub_' & $Double_Count & $Sub_Ext ) & $AVI_Meta
				$String_MKV_File &= ' -s 0 -A -D -T' & $MKV_Meta & ' "' & $TempFolder & 'Sub_' & $Double_Count & $Sub_Ext & '"'
				$String_MP4_File &= ' -add ' & FileGetShortName( $TempFolder & 'Sub_' & $Double_Count & '.srt' ) & $MP4_Meta

				; Increase Active File Count
				$Active_File_Count[0] += 1

				; Add File to File Count
				_ArrayAdd( $Active_File_Count , 'Sub_' & $Double_Count & $Sub_Ext )

				; Test If File Was Actually Created
				If NOT FileExists( $TempFolder & 'Sub_' & $Double_Count & $Sub_Ext ) OR FileGetSize( $TempFolder & 'Sub_' & $Double_Count & $Sub_Ext ) < 2048 Then
					$ErrorLog &= 'Failed to Create Subtitle Stream ' & $Double_Count & ' For:' & @CRLF & $AllFiles[$i] & @CRLF & @CRLF
					$Count_Errors += 1
					ContinueLoop 2
				EndIf

				; Update Current File Progress
				$Stream_Count += 1
			Next
		EndIf

		; Process External Subtitles
		$SubExtensions = StringSplit( '*.aqt;*.asc;*.ass;*.dks;*.lrc;*.mpl;*.ovr;*.pan;*.pjs;*.psb;*.rt;*.rtf;*.s2k;*.sami;*.sbt;*.scr;*.smi;*.son;*.srt;*.ssa;*.sst;*.ssts;*.stl;*.tts;*.vkt;*.vsf;*.zeg' , ';' )
		$MySubExt = ''
		For $a = 1 To $SubExtensions[0]
			$MySubExt &= ';' & $ShortName & $SubExtensions[$a]
		Next
		$AllSubs = _FileListToArrayXT( $FileDir , StringTrimLeft( $MySubExt , 1 ) , 1 , 2 , False , '' , 1 )
		_ArraySort( $AllSubs , 0 , 1 )
		If IsArray( $AllSubs ) = 1 Then
			For $a = 1 To $AllSubs[0]
				; Set Sub Stream Count
				$SubCount = $Streams_Subs[0] + $a

				; Define Macro's
				$SubExt  = StringTrimLeft( $AllSubs[$a] , StringInStr ( $AllSubs[$a] , '.' , 0 , -1 ) - 1 )
				$SubName = StringTrimLeft( $AllSubs[$a] , StringInStr ( $AllSubs[$a] , '\' , 0 , -1 ) )

				; Define FPS
				$SubFPS = StringReplace( $Array_Video[7][1] / $Array_Video[8][1] , '.' , ',' )

				; Double Index Count
				If StringLen( $SubCount ) = 1 Then $Double_Count = '0' & $SubCount
				If StringLen( $SubCount ) = 2 Then $Double_Count = $SubCount

				; RegEx Subtitle Name
				; filename (year) [track] {lang} <title>.ext
				$RegExSubTitle = StringRegExp( $SubName , '(?i)<(.+?)>' , 1 )
				$RegExSubLang  = StringRegExp( $SubName , '(?i)\{(.+?)\}' , 1 )

				; Set AVI Meta
				$AVI_Meta = ''
				If IsArray( $RegExSubLang )  = 1 Then $AVI_Meta &= ' -slang "'             & $RegExSubLang[0]   & '"'
				If IsArray( $RegExSubLang )  = 1 Then $AVI_Meta &= ' -metadata language="' & $RegExSubLang[0]   & '"'
				If IsArray( $RegExSubTitle ) = 1 Then $AVI_Meta &= ' -metadata title="'    & $RegExSubTitle[0]  & '"'

				; Set MKV Meta
				$MKV_Meta = ''
				If IsArray( $RegExSubLang )  = 1 Then $MKV_Meta &= ' --language 0:"'   & $RegExSubLang[0]    & '"'
				If IsArray( $RegExSubTitle ) = 1 Then $MKV_Meta &= ' --track-name 0:"' & $RegExSubTitle[0]   & '"'

				; Set Meta
				$MP4_Meta = ''
				If IsArray( $RegExSubLang )  = 1 Then $MP4_Meta &= ':lang="' & $RegExSubLang[0]  & '"'
				If IsArray( $RegExSubTitle ) = 1 Then $MP4_Meta &= ':name="' & $RegExSubTitle[0] & '"'

				; Update Current Stream Progress
				GUICtrlSetData( $Progress_3 , 0 )

				; Handle Sub Codec's
				Switch $SubExt
					Case '.ASS'
						$Sub_Ext = '.ass'
						RunWait( @ComSpec & ' /c Copy /Y "' & $AllSubs[$a] & '" "' & $TempFolder & 'Sub_' & $Double_Count & '.ass"' , '' , @SW_HIDE )
						RunWait( @ComSpec & ' /c SubtitleWorkshop.exe "/CONVERT(' & $AllSubs[$a] & '/' & $TempFolder & 'Sub_' & $Double_Count & '.srt/SubRip/' & $SubFPS & '/' & $SubFPS & ')"' , @ScriptDir & '\BIN\Subtitle Workshop\' , @SW_HIDE )
					Case '.SRT'
						$Sub_Ext = '.srt'
						RunWait( @ComSpec & ' /c Copy /Y "' & $AllSubs[$a] & '" "' & $TempFolder & 'Sub_' & $Double_Count & '.srt"' , '' , @SW_HIDE )
					Case Else
						$Sub_Ext = '.srt'
						RunWait( @ComSpec & ' /c SubtitleWorkshop.exe "/CONVERT(' & $AllSubs[$a] & '/' & $TempFolder & 'Sub_' & $Double_Count & '.srt/SubRip/' & $SubFPS & '/' & $SubFPS & ')"' , @ScriptDir & '\BIN\Subtitle Workshop\' , @SW_HIDE )
				EndSwitch

				; Set Strings
				$String_AVI_File &= ' -i ' & FileGetShortName( $TempFolder & 'Sub_' & $Double_Count & $Sub_Ext ) & $AVI_Meta
				$String_MKV_File &= ' -s 0 -A -D -T' & $MKV_Meta & ' "' & $TempFolder & 'Sub_' & $Double_Count & $Sub_Ext & '"'
				$String_MP4_File &= ' -add ' & FileGetShortName( $TempFolder & 'Sub_' & $Double_Count & '.srt' ) & $MP4_Meta

				; Test Container Extension
				If $FinalExt <> '.mkv' AND $FinalExt <> '.mp4' Then $FinalExt = '.mkv'

				; Increase Active File Count
				$Active_File_Count[0] += 1

				; Add File to File Count
				_ArrayAdd( $Active_File_Count , 'Sub_' & $Double_Count & $Sub_Ext )

				; Test If File Was Actually Created
				If NOT FileExists( $TempFolder & 'Sub_' & $Double_Count & $Sub_Ext ) OR FileGetSize( $TempFolder & 'Sub_' & $Double_Count & $Sub_Ext ) < 2048 Then
					$ErrorLog &= 'Failed to Create External Subtitle Stream ' & $Double_Count & ' For:' & @CRLF & $AllFiles[$i] & @CRLF & @CRLF
					$Count_Errors += 1
					ContinueLoop 2
				EndIf
			Next
		EndIf

		; Merge Files
		_GUICtrlStatusBar_SetText( $Progress_StatusBar , '  Merging Streams' )
		; Update Current Stream Progress
		GUICtrlSetData( $Progress_3 , 0 )
		Switch $FinalExt
			Case '.mp4'
				$Stream_PID = Run( @ComSpec & ' /c mp4box.exe' & $String_MP4_File & ' -new "' & $TempFolder & $ShortName & $FinalExt & '"' , @ScriptDir & '\BIN\MP4Box\' , @SW_HIDE , $STDERR_CHILD + $STDOUT_CHILD )
				StringReplace( $String_MP4_File , ' -add ' , ' -add ' , 0 , 1 )
				Dim $Stream_Part_All = @Extended + 1
				Dim $Stream_Part
				Dim $Stream_Feed
				Dim $Stream_Percent = 100 / $Stream_Part_All
				; Update Current Stream Progress
				Dim $Stream_Feed
				While 1
					$Stream_Feed = StdoutRead( $Stream_PID )
					If @Error Then ExitLoop
					StringReplace( $Stream_Feed , ' import ' , ' foo ' , 0 , 1 )
					$Stream_Part += @Extended
					If StringInStr( $Stream_Feed , 'Importing' ) Then
						$Feed_Percent = StringRegExp( $Stream_Feed , '(?i)\((\d+)/100\)' , 3 )
						If IsArray( $Feed_Percent ) Then
							$Precent_1 = ( $Feed_Percent[UBound($Feed_Percent) - 1] / $Stream_Part_All ) + ( $Stream_Percent * ( $Stream_Part - 1 ))
							$Precent_2 = ((( $Precent_1 / 100 ) / $Streams_Count_All ) + ( $Stream_Count / $Streams_Count_All )) * 100
							$Precent_3 = ((( $Precent_2 / 100 ) / $Count_Files ) + ( $File_Count / $Count_Files )) * 100
							_UpdateProgress()
						EndIf
					EndIf
					If StringInStr( $Stream_Feed , 'Writing' ) Then
						$Feed_Percent = StringRegExp( $Stream_Feed , '(?i)\((\d+)/100\)' , 3 )
						If IsArray( $Feed_Percent ) Then
							$Precent_1 = ( $Feed_Percent[UBound($Feed_Percent) - 1] / $Stream_Part_All ) + ( $Stream_Percent * ( $Stream_Part - 0 ))
							$Precent_2 = ((( $Precent_1 / 100 ) / $Streams_Count_All ) + ( $Stream_Count / $Streams_Count_All )) * 100
							$Precent_3 = ((( $Precent_2 / 100 ) / $Count_Files ) + ( $File_Count / $Count_Files )) * 100
							_UpdateProgress()
						EndIf
					EndIf
					Sleep( 10 )
				WEnd
			Case '.mkv'
				$Stream_PID = Run( @ComSpec & ' /c mkvmerge.exe -o "' & $TempFolder & $ShortName & $FinalExt & '"' & $String_MKV_File , @ScriptDir & '\BIN\MKVToolNix\' , @SW_HIDE , $STDERR_CHILD + $STDOUT_CHILD )
				; Update Current Stream Progress
				Dim $Stream_Feed
				While 1
					$Stream_Feed = StdoutRead( $Stream_PID )
					If @Error Then ExitLoop
					If StringInStr( $Stream_Feed , 'Progress:' ) Then
						$Feed_Percent = StringRegExp( $Stream_Feed , '(?i)Progress\:\h*(\d+)%' , 3 )
						If IsArray( $Feed_Percent ) Then
							$Precent_1 = $Feed_Percent[UBound($Feed_Percent) - 1]
							$Precent_2 = ((( $Precent_1 / 100 ) / $Streams_Count_All ) + ( $Stream_Count / $Streams_Count_All )) * 100
							$Precent_3 = ((( $Precent_2 / 100 ) / $Count_Files ) + ( $File_Count / $Count_Files )) * 100
							_UpdateProgress()
						EndIf
					EndIf
					Sleep( 10 )
				WEnd
			Case Else
				$Stream_PID = Run( @ComSpec & ' /c ffmpeg.exe' & $String_AVI_File & ' -c copy -y "' & $TempFolder & $ShortName & $FinalExt & '"' , @ScriptDir & '\BIN\FFMpeg\' , @SW_HIDE , $STDERR_CHILD + $STDOUT_CHILD )
				; Update Current Stream Progress
				Dim $Stream_Feed
				While 1
					$Stream_Feed = StderrRead( $Stream_PID )
					If @Error Then ExitLoop
					If StringInStr( $Stream_Feed , 'frame=' ) Then
						$Feed_Count = StringRegExp( $Stream_Feed , '(?i)frame=\h*(\H+)\h' , 3 )
						If IsArray( $Feed_Count ) Then
							$Precent_1 = ( $Feed_Count[UBound( $Feed_Count ) - 1] / $Array_Video[14][1] ) * 100
							$Precent_2 = ((( $Precent_1 / 100 ) / $Streams_Count_All ) + ( $Stream_Count / $Streams_Count_All )) * 100
							$Precent_3 = ((( $Precent_2 / 100 ) / $Count_Files ) + ( $File_Count / $Count_Files )) * 100
							_UpdateProgress()
						EndIf
					EndIf
					Sleep( 10 )
				WEnd
		EndSwitch

		; Update Current File Progress
		$Stream_Count += 1

		; Total Sub Files
		$SubFileSize = 0
		For $c = 1 To $Active_File_Count[0]
			$SubFileSize += FileGetSize( $TempFolder & $Active_File_Count[$c] )
		Next
		$SubFileSize = $SubFileSize * 0.97

		; Get Size
		$Size_Temp = FileGetSize( $AllFiles[$i] )

		; Update Current Stream Progress
		GUICtrlSetData( $Progress_3 , 0 )

		; Replace Orignal
		If FileExists( $TempFolder & $ShortName & $FinalExt ) AND FileGetSize( $TempFolder & $ShortName & $FinalExt ) > $SubFileSize Then
			If $Replace = True Then
				$Size_Old += $Size_Temp
				FileSetAttrib( $AllFiles[$i] , '-RA' )
				FileDelete( $AllFiles[$i] )
				_GUICtrlStatusBar_SetText( $Progress_StatusBar , '  Moving Media' )
				_MyFileCopy( $TempFolder & $ShortName & $FinalExt , $FileDir  & $ShortName & $FinalExt , 2048 )
				$Size_New += FileGetSize( $FileDir  & $ShortName & $FinalExt )
				; Delete External Subtitles
				If IsArray( $AllSubs ) Then
					For $c = 1 To $AllSubs[0]
						$Size_Old += FileGetSize( $AllSubs[$c] )
						FileSetAttrib( $AllSubs[$c] , '-RA' )
						FileDelete( $AllSubs[$c] )
					Next
				EndIf
			Else
				$Size_Old += $Size_Temp
				_GUICtrlStatusBar_SetText( $Progress_StatusBar , '  Moving Media' )
				_MyFileCopy( $TempFolder & $ShortName & $FinalExt , $Complete & $ShortName & $FinalExt , 2048 )
				$Size_New += FileGetSize( $Complete & $ShortName & $FinalExt )
			EndIf
		Else
			$ErrorLog &= 'Failed to Create Finalized Video For:' & @CRLF & $AllFiles[$i] & @CRLF & @CRLF
			$Count_Errors += 1
		EndIf

		; Update Current File Progress
		$Stream_Count += 1
	Next

	; Option Turn Off
	If $Shutdown Then
		; Remove Temp Folder
		_RemoveJunk()
		DirRemove( $TempFolder , 1 )

		; Create Error Log
		_ErrorLog()

		; Invoke ShutDown
		Shutdown( 4 + 1 )
	EndIf

	; Perform Final Operations & Message
	_FinalMessage()
EndFunc

;   //////////////////////////////////////////////////////////////////////////////////////////////////////////////
;  // Sub Functions
; //////////////////////////////////////////////////////////////////////////////////////////////////////////////

Func _Show()
	GUISetState( @SW_SHOW    , $Show_String )
	GUISetState( @SW_RESTORE , $Show_String )
	; Hide the icon
	TraySetState(2)
EndFunc

Func _Hide()
	$Show_String = $Progress
	GUISetState( @SW_HIDE , $Show_String )
	; Show the icon
	TraySetState(1)
EndFunc

Func _Close()
	_WriteSettings()
	Exit
EndFunc

Func _NotEnoughSpaceError( $SelectFile , $SelectDrive )
	$ErrorLog &= 'Not Enough Space On ' & $SelectDrive & ' For:' & @CRLF & $SelectFile & @CRLF & @CRLF
	$Count_Errors += 1
EndFunc

Func _CloseExecutables()
	$Processes = StringSplit( $Executables , '|' )
	For $i = 1 To $Processes[0]
		If ProcessExists( $Processes[$i] ) <> 0 Then ProcessClose( $Processes[$i] )
	Next
EndFunc

Func _RemoveJunk()
	_CloseExecutables()
	FileDelete ( $TempFolder )
	$TempFiles = _FileListToArrayXT( $TempFolder , '*.*' , 1 , 2 , False , '' , 1 )
	If IsArray( $TempFiles ) Then
		For $j = 1 To $TempFiles[0]
			RunWait( @ComSpec & ' /c Unlocker.exe "' & $TempFiles[$j] & '" /S /D' , @ScriptDir & '\BIN\Unlocker\' , @SW_HIDE )
		Next
	EndIf
EndFunc

Func _Exit()
	; Perform Final Operations & Message
	_FinalMessage()

	Exit
EndFunc

Func _FinalMessage()

	; Remove Temp Folder
	_RemoveJunk()
	DirRemove( $TempFolder , 1 )

	; Create Error Log
	_ErrorLog()

	; Clear ToolTip
	TrayTip ( '' , '' , 0 , 16 )

	; Formated File Size Diff
	$Size_Total = $Size_Old - $Size_New
	$Size_GB    = Int( $Size_Total / 1073741824 )
	$Size_MB    = Int( Mod( $Size_Total , 1073741824 ) / 1048576 )
	$Size_KB    = Int( Mod( Mod( $Size_Total , 1073741824 ) , 1048576 ) / 1024 )

	; Formated Lapsed Time.
	$Total_Time = TimerDiff( $Initial_Time )
	$Hours      = Int( $Total_Time / 3600000 )
	$Minutes    = Int( Mod( $Total_Time , 3600000 ) / 60000 )
	$Seconds    = Int( Mod( Mod( $Total_Time , 3600000 ) , 60000 ) / 1000 )

	; Finished String
	$Finished_String = $Count_Files & ' File(s) Processed in -' & @LF
	If $Hours   > 0 Then $Finished_String &= $Hours   & ' Hours '
	If $Minutes > 0 Then $Finished_String &= $Minutes & ' Minutes '
	If $Seconds > 0 Then $Finished_String &= $Seconds & ' Seconds '

	If $Size_Total > 0 Then $Finished_String &= @LF & @LF & 'Total File Savings -' & @LF
	If $Size_GB    > 0 Then $Finished_String &= $Size_GB & ' GB '
	If $Size_MB    > 0 Then $Finished_String &= $Size_MB & ' MB '
	If $Size_KB    > 0 Then $Finished_String &= $Size_KB & ' KB '

	MsgBox( 0 , 'Finished' , $Finished_String & @LF & @LF & 'Total Errors: ' & $Count_Errors )
EndFunc

Func _ErrorLog()
	; Create Error Log
	If StringLen( $ErrorLog ) > 1 Then
		If NOT FileExists( @ScriptDir & '\Error Logs\' ) Then DirCreate ( @ScriptDir & '\Error Logs\' )
		$ErrorLogFile = @ScriptDir & '\Error Logs\[' & @YEAR & '-' & @MON & '-' & @MDAY & '] ' & @HOUR & '-' & @MIN & '.txt'
		FileWrite( $ErrorLogFile , $ErrorLog )
		ShellExecute( $ErrorLogFile )
	EndIf
EndFunc

Func _RegExString( $String , $RegEx )
	Return _ArrayToString( StringRegExp( $String , $RegEx , 1 ))
EndFunc

Func _Toggle_CheckBox( $Form , $Primary , $Secondary )
	Local $ActiveForm = WinGetTitle( $Form )
	If ControlCommand( $ActiveForm , "" , $Secondary , "IsChecked" , "" ) = 1 AND ControlCommand( $ActiveForm , "" , $Primary , "IsChecked" , "" ) = 1 Then
		ControlCommand( $ActiveForm , "" , $Secondary , "UnCheck" , "" )
	EndIf
EndFunc

Func _Convert( $File_In , $File_Out , $Map )
	; FHGaacEnc
;  $Stream_PID = Run( @ComSpec & ' /c .\FFMpeg\ffmpeg.exe -i "' & $File_In  & '" -map 0:' & $Map & ' -c pcm_s16le -f wav - | .\FHGaacEnc\FHGaacEnc.exe --vbr ' & $Quality & ' --ignorelength - "' & $File_Out & '"' , @ScriptDir & '\BIN\' , @SW_HIDE , $STDERR_CHILD + $STDOUT_CHILD )
	; Qaac
;	$Stream_PID = Run( @ComSpec & ' /c .\FFMpeg\ffmpeg.exe -i "' & $File_In & '" -map 0:' & $Map & ' -c pcm_s16le -f wav - | .\Qaac\Qaac.exe -V ' & $Quality & ' -q 2 -i -o "' & $File_Out & '" -' , @ScriptDir & '\BIN\' , @SW_HIDE , $STDERR_CHILD + $STDOUT_CHILD )
	; LAME
	$Stream_PID = Run( @ComSpec & ' /c .\FFMpeg\ffmpeg.exe -i "' & $File_In & '" -map 0:' & $Map & ' -c mp3 -aq ' & $Quality & ' "' & $File_Out & '"' , @ScriptDir & '\BIN\' , @SW_HIDE , $STDERR_CHILD + $STDOUT_CHILD )
	; Update Current Stream Progress
	Dim $Stream_Feed
	While 1
		$Stream_Feed = StderrRead( $Stream_PID )
		If @Error Then ExitLoop
		If StringInStr( $Stream_Feed , 'time=' ) Then
			$Feed_Time = StringRegExp( $Stream_Feed , '(?i)time=\h*(\H+)\h' , 3 )
			If IsArray( $Feed_Time ) Then
				$Feed_Time = StringSplit( $Feed_Time[UBound($Feed_Time) - 1] , ':' )
				$Feed_Time = ((  $Feed_Time[1] * 60 ) * 60 ) + ( $Feed_Time[2] * 60 ) + $Feed_Time[3]

				$Precent_1 = ((  $Feed_Time / $Array_Audio[6][1] ) * 100 ) / 2
				$Precent_2 = ((( $Precent_1 / 100 ) / $Streams_Count_All ) + ( $Stream_Count / $Streams_Count_All )) * 100
				$Precent_3 = ((( $Precent_2 / 100 ) / $Count_Files ) + ( $File_Count / $Count_Files )) * 100
				_UpdateProgress()
			EndIf
		EndIf
		Sleep( 10 )
	WEnd
EndFunc

Func _Sound( $File_In , $File_Out , $Map , $Divisor )
	$Stream_PID = Run(  @ComSpec & ' /c ffmpeg.exe -i "' & $File_In & '" -map 0:' & $Map & ' -c copy -y "' & $File_Out & '"' , @ScriptDir & '\BIN\FFMpeg\' , @SW_HIDE , $STDERR_CHILD + $STDOUT_CHILD )
	; Update Current Stream Progress
	Dim $Stream_Feed
	While 1
		$Stream_Feed = StderrRead( $Stream_PID )
		If @Error Then ExitLoop
		If StringInStr( $Stream_Feed , 'time=' ) Then
			$Feed_Time = StringRegExp( $Stream_Feed , '(?i)time=\h*(\H+)\h' , 3 )
			If IsArray( $Feed_Time ) Then
				$Feed_Time = StringSplit( $Feed_Time[UBound($Feed_Time) - 1] , ':' )
				$Feed_Time = (( $Feed_Time[1] * 60 ) * 60 ) + ( $Feed_Time[2] * 60 ) + $Feed_Time[3]
				$Precent_1 = (( $Feed_Time / $Array_Audio[6][1] ) * 100 ) / $Divisor
				$Precent_2 = ((( $Precent_1 / 100 ) / $Streams_Count_All ) + ( $Stream_Count / $Streams_Count_All )) * 100
				$Precent_3 = ((( $Precent_2 / 100 ) / $Count_Files ) + ( $File_Count / $Count_Files )) * 100
				_UpdateProgress()
			EndIf
		EndIf
		Sleep( 10 )
	WEnd
EndFunc

Func _AACGain( $File_In )
	; Get File Size to Wait Time
	; Wait per 40mb
	$SizeWait = ( FileGetSize( $File_In ) / 1048576 ) / 40
	If $SizeWait < 1 Then $SizeWait = 1

	; Apply Gain to AAC - Default 89db or Lower if Clipping Present
	$Stream_PID = Run( @ComSpec & ' /c aacgain.exe /s r /r /k /f "' & $File_In & '"' , @ScriptDir & '\BIN\AAC Gain\' , @SW_HIDE , $STDERR_CHILD + $STDOUT_CHILD )
	; Update Current Stream Progress
	Dim $Stream_Feed
	While 1
		$Stream_Feed = StderrRead( $Stream_PID )
		If @Error Then ExitLoop
		If StringInStr( $Stream_Feed , 'analyzed' ) Then
			$Feed_Time = StringRegExp( $Stream_Feed , '(?i)(\d+)%' , 3 )
			If IsArray( $Feed_Time ) Then
				$Precent_1 = ((( $Feed_Time[UBound($Feed_Time) - 1] / 100 ) * 100 ) / 4 ) + 50
				$Precent_2 = ((( $Precent_1 / 100 ) / $Streams_Count_All ) + ( $Stream_Count / $Streams_Count_All )) * 100
				$Precent_3 = ((( $Precent_2 / 100 ) / $Count_Files ) + ( $File_Count / $Count_Files )) * 100
				_UpdateProgress()
			EndIf
		EndIf
		If StringInStr( $Stream_Feed , 'written' ) Then
			$Feed_Time = StringRegExp( $Stream_Feed , '(?i)(\d+)%' , 3 )
			If IsArray( $Feed_Time ) Then
				$Precent_1 = ((( $Feed_Time[UBound($Feed_Time) - 1] / 100 ) * 100 ) / 4 ) + 75
				$Precent_2 = ((( $Precent_1 / 100 ) / $Streams_Count_All ) + ( $Stream_Count / $Streams_Count_All )) * 100
				$Precent_3 = ((( $Precent_2 / 100 ) / $Count_Files ) + ( $File_Count / $Count_Files )) * 100
				_UpdateProgress()
			EndIf
		EndIf
		Sleep( 10 )
	WEnd

	; AACGain Often Finishes Prior To File
	; Being Written Out, Causing a Lock
	; Wait 1sec per
	Sleep( Int( $SizeWait * 1500 ))
EndFunc

Func _MyFileCopy( $inSource , $inDest , $ChunkSize = 2048 )
	; Open Source File for BINARY reading
	$SourceFile = FileOpen( $inSource , 16 )
	; Open Destination File for BINARY Writing,
	; OverWriting Existing File,
	; Creating Directory Structure
	$DestinFile = FileOpen( $inDest , 26 )
	; Get the Size of the File We are Going to Copy
	$SourceSize = FileGetSize( $inSource )
	; Calculate How Many Chunks We Need to Copy
	$Chunks = $SourceSize / $ChunkSize
	; Loop From 0 to Number of Chunks
	For $i = 0 To $Chunks
		; Read the Next Chunk
		$Data = FileRead( $SourceFile , $ChunkSize )
		; Write the Next Chunk
		FileWrite( $DestinFile , $Data )
		; Update Current Stream Progress
		$Precent_1 = (( $i + 1 ) / $Chunks ) * 100
		$Precent_2 = ((( $Precent_1 / 100 ) / $Streams_Count_All ) + ( $Stream_Count / $Streams_Count_All )) * 100
		$Precent_3 = ((( $Precent_2 / 100 ) / $Count_Files ) + ( $File_Count / $Count_Files )) * 100
		_UpdateProgress()
	Next
	; Close the Source File
	FileClose( $SourceFile )
	; Close the Destination File
	FileClose( $DestinFile )
EndFunc

Func _UpdateProgress()
	GUICtrlSetData( $Progress_1 , Int( $Precent_3 ))
	GUICtrlSetData( $Progress_2 , Int( $Precent_2 ))
	GUICtrlSetData( $Progress_3 , Int( $Precent_1 ))
EndFunc

Func _BasicSettings()
	$BasicSettings = ''
	$BasicSettings &= '[H264]'          & @CRLF
	$BasicSettings &= 'Encode=False'    & @CRLF
	$BasicSettings &= 'Preset=Medium'   & @CRLF
	$BasicSettings &= 'Tuning=Film'     & @CRLF
	$BasicSettings &= 'Quality=23'      & @CRLF
	$BasicSettings &= @CRLF
	$BasicSettings &= '[Force]'         & @CRLF
	$BasicSettings &= 'MKV=True'        & @CRLF
	$BasicSettings &= 'MP4=False'       & @CRLF
	$BasicSettings &= 'Replace=False'   & @CRLF
	$BasicSettings &= @CRLF
	$BasicSettings &= '[Deinterlace]'   & @CRLF
	$BasicSettings &= 'Value=False'     & @CRLF
	$BasicSettings &= @CRLF
	$BasicSettings &= '[Encoder]'       & @CRLF
	$BasicSettings &= 'Value=x264 8bit' & @CRLF
	$BasicSettings &= @CRLF
	$BasicSettings &= '[Preserve]'      & @CRLF
	$BasicSettings &= 'AC3=False'       & @CRLF
	$BasicSettings &= 'DTS=False'       & @CRLF
	$BasicSettings &= @CRLF
	$BasicSettings &= '[Settings]'      & @CRLF
	$BasicSettings &= 'Quality=40'      & @CRLF
	$BasicSettings &= 'Recurse=False'   & @CRLF
	$BasicSettings &= 'Shutdown=False'  & @CRLF
	$BasicSettings &= @CRLF
	$BasicSettings &= '[Last Path]'     & @CRLF
	$BasicSettings &= 'Path='           & @CRLF
	FileWrite( $SavedSettings , $BasicSettings )
EndFunc

Func _CheckGUIArray( $MyValue , $MyArray , $MyDefault )
	$MyNewArray = StringSplit( $MyArray , '|' )
	_ArraySearch( $MyNewArray , $MyValue , 1 )
	If @Error Then
		Return $MyDefault
	Else
		Return $MyValue
	EndIf
EndFunc

Func _WriteSettings()
	If GUICtrlRead( $FFMpeg    ) = 1 Then $MyINIEncoder = 'FFMpeg'
	If GUICtrlRead( $x264_8bit ) = 1 Then $MyINIEncoder = 'x264 8bit'
	If GUICtrlRead( $x264_10bit) = 1 Then $MyINIEncoder = 'x264 10bit'

	IniWrite( $SavedSettings , 'Force' , 'MKV'    , _getControlBoolString( $ChkBox_MKV ))
	IniWrite( $SavedSettings , 'Force' , 'MP4'    , _getControlBoolString( $ChkBox_MP4 ))
	IniWrite( $SavedSettings , 'Force' , 'Replace', _getControlBoolString( $ChkBox_Replace ))

	IniWrite( $SavedSettings , 'H264' , 'Encode' , _getControlBoolString( $ChkBox_Encode ))
	IniWrite( $SavedSettings , 'H264' , 'Preset' , GUICtrlRead( $Combo_Preset ))
	IniWrite( $SavedSettings , 'H264' , 'Tuning' , GUICtrlRead( $Combo_Tuning ))
	IniWrite( $SavedSettings , 'H264' , 'Quality', GUICtrlRead( $Combo_Quality))

	IniWrite( $SavedSettings , 'Deinterlace'  , 'Value' , _getControlBoolString( $DI_Yes ))
	IniWrite( $SavedSettings , 'Encoder'      , 'Value' , $MyINIEncoder )

	IniWrite( $SavedSettings , 'Preserve' , 'AC3' , _getControlBoolString( $ChkBox_AC3 ))
	IniWrite( $SavedSettings , 'Preserve' , 'DTS' , _getControlBoolString( $ChkBox_DTS ))

	IniWrite( $SavedSettings , 'Settings' , 'Quality' , GUICtrlRead( $Combo_Audio ))
	IniWrite( $SavedSettings , 'Settings' , 'Recurse' , _getControlBoolString( $ChkBox_Recurse ))
	IniWrite( $SavedSettings , 'Settings' , 'Shutdown', _getControlBoolString( $ChkBox_Shutdown ))

	IniWrite( $SavedSettings , 'Last Path' , 'Path' , GUICtrlRead( $Input_FolderPath ))
EndFunc

Func _getControlBoolString( $Control )
	If GUICtrlRead( $Control ) =  1 Then Return 'True'
	If GUICtrlRead( $Control ) <> 1 Then Return 'False'
EndFunc

Func _getControlBoolValue( $Control )
	If GUICtrlRead( $Control ) =  1 Then Return True
	If GUICtrlRead( $Control ) <> 1 Then Return False
EndFunc

Func _getExecutables()
	$ExecutableArray = _FileListToArrayXT( @ScriptDir , '*.exe' , 1 , 0 , True , '' , 1 )
	_ArraySort( $ExecutableArray , 0 , 1 )
	$FindVG = _ArrayFindAll( $ExecutableArray , @ScriptName , 1 )
	If IsArray( $FindVG ) Then
		$i = UBound( $FindVG ) - 1
		Do
			_ArrayDelete( $ExecutableArray , $FindVG[$i] )
			$ExecutableArray[0] -= 1
			$i -= 1
		Until $i < 0
	EndIf
	Global $Executables = 'cmd.exe'
	For $i = 1 To $ExecutableArray[0]
		$Executables &= '|' & $ExecutableArray[$i]
	Next
EndFunc

; #FUNCTION# ===========================================================================================
; Name:             _FileListToArrayXT
; Description:      Lists files and\or folders in specified path(s) (Similar to using Dir with the /B Switch)
;                   additional features: multi-path, multi-filter, multi-exclude-filter, path format options, recursive search
;                   Corrected on 2010/08/19: Added FileClose()
; Syntax:           _FileListToArrayXT([$sPath = @ScriptDir, [$sFilter = "*", [$iRetItemType, [$bRecursive = False, [$sExclude = "", [$iRetFormat = 1]]]]]])
; Parameter(s):     $sPath = optional: Search path(s), semicolon delimited (default: @ScriptDir)
;                            (Example: "C:\Tmp;D:\Temp")
;                   $sFilter = optional: Search filter(s), semicolon delimited . Wildcards allowed. (default: "*")
;                              (Example: "*.exe;*.txt")
;                   $iRetItemType = Include in search: 0 = Files and Folder, 1 = Files Only, 2 = Folders Only
;                   $iRetPathType = Returned element format: 0 = file/folder name only, 1 = relative path, 2 = full path
;                   $bRecursive = optional: True: recursive search including all subdirectories
;                                           False (default): search only in specified folder
;                   $sExclude = optional: Exclude filter(s), semicolon delimited. Wildcards allowed.
;                               (Example: "Unins*" will remove all files/folders that begin with "Unins")
;                   $iRetFormat =  optional: return format
;                                  0 = one-dimensional array, 0-based
;                                  1 = one-dimensional array, 1-based (default)
;                                  2 = String ( "|" delimited)
; Requirement(s):   AutoIt Version 3.3.1.1 or newer
; Return Value(s):  on success: 1-based or 0-based array or string (dependent on $iRetFormat)
;                   If no path is found, @error and @extended are set to 1, returns empty string
;                   If no filter is found, @error and @extended are set to 2, returns empty string
;                   If $iRetFormat is invalid, @error and @extended are set to 3, returns empty string
;                   If no data is found, @error and @extended are set to 4, returns empty string
; Author(s):        Half the AutoIt Community
; ====================================================================================================
Func _FileListToArrayXT($sPath = @ScriptDir, $sFilter = "*", $iRetItemType = 0, $iRetPathType = 0, $bRecursive = False, $sExclude = "", $iRetFormat = 1)
	Local $hSearchFile, $sFile, $sFileList, $sWorkPath, $sRetPath, $iRootPathLen, $iPCount, $iFCount, $fDirFlag

	;[Check And Prepare Parameters]
	;---------------
	If $sPath = -1 OR $sPath = Default Then $sPath = @ScriptDir
	; Strip Leading/Trailing Spaces And Semi-Colons, All Adjacent Semi-Colons, And Spaces Surrounding Semi-Colons
	$sPath = StringRegExpReplace(StringRegExpReplace($sPath, "(\s*;\s*)+", ";"), "\A;|;\z", "")
	; Check That At Least One Path Is Set
	If $sPath = "" Then Return SetError(1, 1, "")
	;-----
	If $sFilter = -1 OR $sFilter = Default Then $sFilter = "*"
	; Prepare Filter
	; Strip Leading/Trailing Spaces And Semi-Colons, All Adjacent Semi-Colons, And Spaces Surrounding Semi-Colons
	$sFilter = StringRegExpReplace(StringRegExpReplace($sFilter, "(\s*;\s*)+", ";"), "\A;|;\z", "")
	; Check For Invalid Chars Or That At Least One Filter Is Set
	If StringRegExp($sFilter, "[\\/><:\|]|(?s)\A\s*\z") Then Return SetError(2, 2, "")
	If $bRecursive Then
		;Convert $sFilter for Regular Expression
		$sFilter = StringRegExpReplace($sFilter, '([\Q\.+[^]$(){}=!\E])', '\\$1')
		$sFilter = StringReplace($sFilter, "?", ".")
		$sFilter = StringReplace($sFilter, "*", ".*?")
		$sFilter = "(?i)\A(" & StringReplace($sFilter, ";", "$|") & "$)"  ; Case-Insensitive, Convert ';' To '|', Match From First Char, Terminate Strings
		;$sFilter = "(?i)\A" & StringReplace($sFilter, ";", "|") & "\z"
	EndIf
	;-----
	If $iRetItemType <> "1" AND $iRetItemType <> "2" Then $iRetItemType = "0"
	;-----
	If $iRetPathType <> "1" AND $iRetPathType <> "2" Then $iRetPathType = "0"
	;-----
	$bRecursive = ($bRecursive = "1")
	;-----
	If $sExclude = -1 OR $sExclude = Default Then $sExclude = ""
	If $sExclude Then
	  ; Prepare $sExclude
	  ; Strip Leading/Trailing Spaces And Semi-Colons, All Adjacent Semi-Colons, And Spaces Surrounding Semi-Colons
	  $sExclude = StringRegExpReplace(StringRegExpReplace($sExclude, "(\s*;\s*)+", ";"), "\A;|;\z", "")
	  ; Convert $sExclude for Regular Expression
	  $sExclude = StringRegExpReplace($sExclude, '([\Q\.+[^]$(){}=!\E])', '\\$1')
	  $sExclude = StringReplace($sExclude, "?", ".")
	  $sExclude = StringReplace($sExclude, "*", ".*?")
	  $sExclude = "(?i)\A(" & StringReplace($sExclude, ";", "$|") & "$)" ; Case-Insensitive, Convert ';' To '|', Match From First Char, Terminate Strings
	  ;$sExclude = "(?i)\A" & StringReplace($sExclude, ";", "|") & "\z"
	EndIf
	;-----
	; If $iRetFormat <> "0" And $iRetFormat <> "2" Then $iRetFormat = "1"
	If NOT ($iRetItemType = 0 OR $iRetItemType = 1 OR $iRetItemType = 2) Then Return SetError(3, 3, "")
	;---------------
	;[/Check And Prepare Parameters]

	;---------------

	Local $aPath = StringSplit($sPath, ';', 1)      ; Paths Array
	Local $aFilter = StringSplit($sFilter, ';', 1)  ; Filters Array

	;---------------

	; Different Handling For Recursion (Strategy: Unfiltered Search For All Items And Filter Unwanted)
	If $bRecursive Then
		; Different Handling Dependent On $Sexclude Parameter Is Set Or Not
		If $sExclude Then
			; Path Loop
			For $iPCount = 1 To $aPath[0]
				; Ensure Exact One Trailing Slash
				$sPath = StringRegExpReplace($aPath[$iPCount], "[\\/]+\z", "") & "\"
				If NOT FileExists($sPath) Then ContinueLoop
				$iRootPathLen = StringLen($sPath) - 1

				Local $aPathStack[1024] = [1, $sPath]

				While $aPathStack[0] > 0
					$sWorkPath = $aPathStack[$aPathStack[0]]
					$aPathStack[0] -= 1
					;-----
					$hSearchFile = FileFindFirstFile($sWorkPath & '*')
					If @Error Then
						FileClose($hSearchFile)
						ContinueLoop
					EndIf
					;-----
					Switch $iRetPathType
						; Full Path
						Case 2
							$sRetPath = $sWorkPath
						; Relative Path
						Case 1
							$sRetPath = StringTrimLeft($sWorkPath, $iRootPathLen + 1)
					EndSwitch
					;-----
					Switch $iRetItemType
						; Files Only
						Case 1
							While True
								$sFile = FileFindNextFile($hSearchFile)
								If @Error Then
									FileClose($hSearchFile)
									ExitLoop
								EndIf
								$fDirFlag = @Extended
								If $fDirFlag Then
									$aPathStack[0] += 1
									If UBound($aPathStack) <= $aPathStack[0] Then ReDim $aPathStack[UBound($aPathStack) * 2]
									$aPathStack[$aPathStack[0]] = $sWorkPath & $sFile & "\"
									ContinueLoop
								EndIf
								If StringRegExp($sFile, $sExclude) Then ContinueLoop
								If StringRegExp($sFile, $sFilter) Then
									$sFileList &= $sRetPath & $sFile & "|"
								EndIf
							WEnd
						; FoldeRs Only
						Case 2
							While True
								$sFile = FileFindNextFile($hSearchFile)
								If @Error Then
									FileClose($hSearchFile)
									ExitLoop
								EndIf
								$fDirFlag = @Extended
								If StringRegExp($sFile, $sExclude) Then ContinueLoop
								If $fDirFlag Then
									$aPathStack[0] += 1
									If UBound($aPathStack) <= $aPathStack[0] Then ReDim $aPathStack[UBound($aPathStack) * 2]
									$aPathStack[$aPathStack[0]] = $sWorkPath & $sFile & "\"
									If StringRegExp($sFile, $sFilter) Then
										$sFileList &= $sRetPath & $sFile & "|"
									EndIf
								EndIf
							WEnd
						; Files And Folders
						Case Else
							While True
								$sFile = FileFindNextFile($hSearchFile)
								If @Error Then
									FileClose($hSearchFile)
									ExitLoop
								EndIf
								$fDirFlag = @Extended
								If StringRegExp($sFile, $sExclude) Then ContinueLoop
								If $fDirFlag Then
									$aPathStack[0] += 1
									If UBound($aPathStack) <= $aPathStack[0] Then ReDim $aPathStack[UBound($aPathStack) * 2]
									$aPathStack[$aPathStack[0]] = $sWorkPath & $sFile & "\"
								EndIf
								If StringRegExp($sFile, $sFilter) Then
									$sFileList &= $sRetPath & $sFile & "|"
								EndIf
							WEnd
					EndSwitch
					;-----
				WEnd
				FileClose($hSearchFile)
			; $iPCount - Next Path
			Next
		; If Not $sExclude
		Else
			; Path Loop
			For $iPCount = 1 To $aPath[0]
				; Ensure Exact One Trailing Slash
				$sPath = StringRegExpReplace($aPath[$iPCount], "[\\/]+\z", "") & "\"
				If NOT FileExists($sPath) Then ContinueLoop
				$iRootPathLen = StringLen($sPath) - 1

				Local $aPathStack[1024] = [1, $sPath]

				While $aPathStack[0] > 0
					$sWorkPath = $aPathStack[$aPathStack[0]]
					$aPathStack[0] -= 1
					;-----
					$hSearchFile = FileFindFirstFile($sWorkPath & '*')
					If @Error Then
						FileClose($hSearchFile)
						ContinueLoop
					EndIf
					;-----
					Switch $iRetPathType
						; Full Path
						Case 2
							$sRetPath = $sWorkPath
						; Relative Path
						Case 1
							$sRetPath = StringTrimLeft($sWorkPath, $iRootPathLen + 1)
					EndSwitch
					;-----
					Switch $iRetItemType
						; Files Only
						Case 1
							While True
								$sFile = FileFindNextFile($hSearchFile)
								If @Error Then
									FileClose($hSearchFile)
									ExitLoop
								EndIf
								If @Extended Then
									$aPathStack[0] += 1
									If UBound($aPathStack) <= $aPathStack[0] Then ReDim $aPathStack[UBound($aPathStack) * 2]
									$aPathStack[$aPathStack[0]] = $sWorkPath & $sFile & "\"
									ContinueLoop
								EndIf
								If StringRegExp($sFile, $sFilter) Then
									$sFileList &= $sRetPath & $sFile & "|"
								EndIf
							WEnd
						; Folders Only
						Case 2
							While True
								$sFile = FileFindNextFile($hSearchFile)
								If @Error Then
									FileClose($hSearchFile)
									ExitLoop
								EndIf
								If @Extended Then
									$aPathStack[0] += 1
									If UBound($aPathStack) <= $aPathStack[0] Then ReDim $aPathStack[UBound($aPathStack) * 2]
									$aPathStack[$aPathStack[0]] = $sWorkPath & $sFile & "\"
									If StringRegExp($sFile, $sFilter) Then
										$sFileList &= $sRetPath & $sFile & "|"
									EndIf
								EndIf
							WEnd
						; Files And Folders
						Case Else
							While True
								$sFile = FileFindNextFile($hSearchFile)
								If @Error Then
									FileClose($hSearchFile)
									ExitLoop
								EndIf
								If @Extended Then
									$aPathStack[0] += 1
									If UBound($aPathStack) <= $aPathStack[0] Then ReDim $aPathStack[UBound($aPathStack) * 2]
									$aPathStack[$aPathStack[0]] = $sWorkPath & $sFile & "\"
								EndIf
								If StringRegExp($sFile, $sFilter) Then
									$sFileList &= $sRetPath & $sFile & "|"
								EndIf
							WEnd
					EndSwitch
					;-----
				WEnd
				FileClose($hSearchFile)
			; $iPCount - Next Path
			Next
		; If $sExclude
		EndIf
	; If Not $bRecursive (Strategy: Filtered Search For Items)
	Else
		; Different Handling Dependent On $Sexclude Parameter Is Set Or Not
		If $sExclude Then
			; Path Loop
			For $iPCount = 1 To $aPath[0]
				; Ensure Exact One Trailing Slash
				$sPath = StringRegExpReplace($aPath[$iPCount], "[\\/]+\z", "") & "\"
				If NOT FileExists($sPath) Then ContinueLoop
				;-----
				Switch $iRetPathType
					; Full Path
					Case 2
						$sRetPath = $sPath
					; Relative Path
					Case 1
						$sRetPath = ""
				EndSwitch

				; Filter Loop
				For $iFCount = 1 To $aFilter[0]
					;-----
					$hSearchFile = FileFindFirstFile($sPath & $aFilter[$iFCount])
					If @Error Then
						FileClose($hSearchFile)
						ContinueLoop
					EndIf
					;-----
					Switch $iRetItemType
						; Files Only
						Case 1
							While True
								$sFile = FileFindNextFile($hSearchFile)
								If @Error Then
									FileClose($hSearchFile)
									ExitLoop
								EndIf
								; Bypass Folder
								If @Extended Then ContinueLoop
								; Check For Exclude Files
								If StringRegExp($sFile, $sExclude) Then ContinueLoop
								$sFileList &= $sRetPath & $sFile & "|"
							WEnd
						; Folders Only
						Case 2
							While True
								$sFile = FileFindNextFile($hSearchFile)
								If @Error Then
									FileClose($hSearchFile)
									ExitLoop
								EndIf
								; Bypass File
								If @Extended Then
									; Check For Exclude Folder
									If StringRegExp($sFile, $sExclude) Then ContinueLoop
									$sFileList &= $sRetPath & $sFile & "|"
								EndIf
							WEnd
						; Files And Folders
						Case Else
							While True
								$sFile = FileFindNextFile($hSearchFile)
								If @Error Then
									FileClose($hSearchFile)
									ExitLoop
								EndIf
								; Check For Exclude Files/Folder
								If StringRegExp($sFile, $sExclude) Then ContinueLoop
								$sFileList &= $sRetPath & $sFile & "|"
							WEnd
					EndSwitch
					FileClose($hSearchFile)
				; $iFCount - Next Filter
				Next
			; $iPCount - Next Path
			Next
		; If Not $sExclude
		Else
			; Path Loop
			For $iPCount = 1 To $aPath[0]
				; Ensure Exact One Trailing Slash
				$sPath = StringRegExpReplace($aPath[$iPCount], "[\\/]+\z", "") & "\"
				If NOT FileExists($sPath) Then ContinueLoop
				;-----
				Switch $iRetPathType
					; Full Path
					Case 2
						$sRetPath = $sPath
					; Relative Path
					Case 1
						$sRetPath = ""
				EndSwitch

				; Filter Loop
				For $iFCount = 1 To $aFilter[0]
					;-----
					$hSearchFile = FileFindFirstFile($sPath & $aFilter[$iFCount])
					If @Error Then
						FileClose($hSearchFile)
						ContinueLoop
					EndIf
					;-----
					Switch $iRetItemType
						; Files Only
						Case 1
							While True
								$sFile = FileFindNextFile($hSearchFile)
								If @Error Then
									FileClose($hSearchFile)
									ExitLoop
								EndIf
								; Bypass Folder
								If @Extended Then ContinueLoop
								$sFileList &= $sRetPath & $sFile & "|"
							WEnd
						; Folders Only
						Case 2
							While True
								$sFile = FileFindNextFile($hSearchFile)
								If @Error Then
									FileClose($hSearchFile)
									ExitLoop
								EndIf
								; Bypass File
								If @Extended Then
									$sFileList &= $sRetPath & $sFile & "|"
								EndIf
							WEnd
						; Files And Folders
						Case Else
							While True
								$sFile = FileFindNextFile($hSearchFile)
								If @Error Then
									FileClose($hSearchFile)
									ExitLoop
								EndIf
								$sFileList &= $sRetPath & $sFile & "|"
							WEnd
					EndSwitch
					FileClose($hSearchFile)
				;$iFCount - Next Filter
				Next
			; $iPCount - Next Path
			Next
		; If $sExclude
		EndIf
	; If $bRecursive
	EndIf

	;---------------

	; Set According Return Value
	If $sFileList Then
		Switch $iRetFormat
			; Return A Delimited String
			Case 2
				Return StringTrimRight($sFileList, 1)
			; Return A 0-Based Array
			Case 0
				Return StringSplit(StringTrimRight($sFileList, 1), "|", 2)
			; Return A 1-Based Array
			Case Else
				Return StringSplit(StringTrimRight($sFileList, 1), "|", 1)
		EndSwitch
	Else
		Return SetError(4, 4, "")
	EndIf
EndFunc   ;==>_FileListToArrayX
